package com.gitee.ywj1352.client.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Stream;

public class RpcRegister implements ImportBeanDefinitionRegistrar, BeanFactoryAware, EnvironmentAware {
    private BeanFactory beanFactory;

    private Environment environment;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        Map<String, Object> attributes =
                annotationMetadata.getAnnotationAttributes(EnableRpc.class.getName());
        Class<?>[] clazzs = (Class[])attributes.get("clients");

        ClassLoader classLoader = this.getClass().getClassLoader();
        Stream.of(clazzs).filter(Class::isInterface)
                //.filter(clazz-> AnnotationUtils.findAnnotation(clazz, RestClient.class)!=null)
        .forEach(interfaceClazz->{
            Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{interfaceClazz}, null);
            String beanName = "RestClient" + interfaceClazz.getName();
            if(registry instanceof SingletonBeanRegistry){
                //使用SingletonBeanRegistry 来注册
                ((SingletonBeanRegistry) registry).registerSingleton(beanName,proxy);
            }else {
                BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(RpcClientClassFactoryBean.class);
                //增加第一个构造器参数引用
                beanDefinitionBuilder.addConstructorArgValue(proxy);
                beanDefinitionBuilder.addConstructorArgValue(interfaceClazz);
                //把 代理类 注册到  spring 容器中
                registry.registerBeanDefinition(beanName,beanDefinitionBuilder.getBeanDefinition());
            }
        });

    }

    /**
     * 因为 被代理 对象是接口  所以只能使用FactoryBean 给他 注入到 Spring 容器中
     */
    private static class RpcClientClassFactoryBean implements FactoryBean {
        private final Class<?> restClient;
        private final Object proxy;

        public RpcClientClassFactoryBean(Object proxy,Class<?> restClient) {
            this.restClient = restClient;
            this.proxy = proxy;
        }
        @Override
        public Object getObject() throws Exception {
            return proxy;
        }
        @Override
        public Class<?> getObjectType() {
            return restClient;
        }
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
}

